#!/usr/bin/env python3
"""
性能监控模块
实时监控系统性能和资源使用情况
"""

import time
import threading
import psutil
import json
from typing import Dict, Any, List, Optional, Callable
from dataclasses import dataclass, asdict
from datetime import datetime
from collections import deque
import queue


@dataclass
class PerformanceMetrics:
    """性能指标数据类"""
    timestamp: float
    cpu_percent: float
    memory_percent: float
    memory_used_mb: float
    disk_usage_percent: float
    network_sent_mb: float
    network_recv_mb: float
    active_threads: int
    active_connections: int
    custom_metrics: Dict[str, float] = None
    
    def __post_init__(self):
        if self.custom_metrics is None:
            self.custom_metrics = {}


@dataclass
class ResourceAlert:
    """资源警报"""
    timestamp: float
    alert_type: str
    message: str
    severity: str  # 'info', 'warning', 'error', 'critical'
    value: float
    threshold: float


class PerformanceMonitor:
    """性能监控器"""
    
    def __init__(self, 
                 sampling_interval: float = 1.0,
                 history_size: int = 3600,  # 1小时的历史数据
                 enable_alerts: bool = True):
        """
        初始化性能监控器
        
        Args:
            sampling_interval: 采样间隔（秒）
            history_size: 历史数据大小
            enable_alerts: 是否启用警报
        """
        self.sampling_interval = sampling_interval
        self.history_size = history_size
        self.enable_alerts = enable_alerts
        
        # 数据存储
        self.metrics_history = deque(maxlen=history_size)
        self.alerts = deque(maxlen=100)
        
        # 监控状态
        self.running = False
        self.monitor_thread = None
        
        # 警报阈值
        self.alert_thresholds = {
            'cpu_percent': {'warning': 80, 'critical': 95},
            'memory_percent': {'warning': 80, 'critical': 95},
            'disk_percent': {'warning': 85, 'critical': 95},
            'active_threads': {'warning': 100, 'critical': 200}
        }
        
        # 网络统计基准
        self.network_stats = psutil.net_io_counters()
        self.last_network_time = time.time()
        
        # 回调函数
        self.metric_callback: Optional[Callable] = None
        self.alert_callback: Optional[Callable] = None
        
        # 自定义指标
        self.custom_metrics = {}
        
        # 进程信息
        self.process = psutil.Process()
        
        # 性能统计
        self.performance_stats = {
            'total_samples': 0,
            'avg_cpu': 0.0,
            'avg_memory': 0.0,
            'peak_cpu': 0.0,
            'peak_memory': 0.0,
            'alert_count': 0
        }
    
    def start(self):
        """启动监控"""
        if self.running:
            return
        
        self.running = True
        self.monitor_thread = threading.Thread(target=self._monitor_loop)
        self.monitor_thread.daemon = True
        self.monitor_thread.start()
    
    def stop(self):
        """停止监控"""
        self.running = False
        if self.monitor_thread:
            self.monitor_thread.join(timeout=2.0)
    
    def set_metric_callback(self, callback: Callable[[PerformanceMetrics], None]):
        """设置指标回调函数"""
        self.metric_callback = callback
    
    def set_alert_callback(self, callback: Callable[[ResourceAlert], None]):
        """设置警报回调函数"""
        self.alert_callback = callback
    
    def add_custom_metric(self, name: str, value: float):
        """添加自定义指标"""
        self.custom_metrics[name] = value
    
    def _monitor_loop(self):
        """监控循环"""
        while self.running:
            try:
                # 收集指标
                metrics = self._collect_metrics()
                
                # 更新历史记录
                self.metrics_history.append(metrics)
                
                # 更新统计信息
                self._update_stats(metrics)
                
                # 检查警报
                if self.enable_alerts:
                    self._check_alerts(metrics)
                
                # 调用回调函数
                if self.metric_callback:
                    self.metric_callback(metrics)
                
                # 等待下次采样
                time.sleep(self.sampling_interval)
                
            except Exception as e:
                print(f"监控错误: {e}")
                time.sleep(1.0)
    
    def _collect_metrics(self) -> PerformanceMetrics:
        """收集性能指标"""
        # CPU 使用率
        cpu_percent = self.process.cpu_percent()
        
        # 内存使用
        memory_info = self.process.memory_info()
        memory_percent = self.process.memory_percent()
        memory_used_mb = memory_info.rss / 1024 / 1024
        
        # 磁盘使用（当前磁盘）
        disk_usage = psutil.disk_usage('/')
        disk_percent = disk_usage.percent
        
        # 网络统计
        current_time = time.time()
        time_diff = current_time - self.last_network_time
        current_net_stats = psutil.net_io_counters()
        
        if time_diff > 0:
            network_sent = (current_net_stats.bytes_sent - self.network_stats.bytes_sent) / 1024 / 1024 / time_diff
            network_recv = (current_net_stats.bytes_recv - self.network_stats.bytes_recv) / 1024 / 1024 / time_diff
        else:
            network_sent = 0
            network_recv = 0
        
        self.network_stats = current_net_stats
        self.last_network_time = current_time
        
        # 活跃线程数
        active_threads = self.process.num_threads()
        
        # 活跃连接数
        active_connections = len(self.process.connections())
        
        # 创建指标对象
        metrics = PerformanceMetrics(
            timestamp=time.time(),
            cpu_percent=cpu_percent,
            memory_percent=memory_percent,
            memory_used_mb=memory_used_mb,
            disk_usage_percent=disk_percent,
            network_sent_mb=network_sent,
            network_recv_mb=network_recv,
            active_threads=active_threads,
            active_connections=active_connections,
            custom_metrics=self.custom_metrics.copy()
        )
        
        return metrics
    
    def _update_stats(self, metrics: PerformanceMetrics):
        """更新统计信息"""
        self.performance_stats['total_samples'] += 1
        
        # 计算平均值
        total = self.performance_stats['total_samples']
        self.performance_stats['avg_cpu'] = (
            (self.performance_stats['avg_cpu'] * (total - 1) + metrics.cpu_percent) / total
        )
        self.performance_stats['avg_memory'] = (
            (self.performance_stats['avg_memory'] * (total - 1) + metrics.memory_percent) / total
        )
        
        # 更新峰值
        self.performance_stats['peak_cpu'] = max(
            self.performance_stats['peak_cpu'], metrics.cpu_percent
        )
        self.performance_stats['peak_memory'] = max(
            self.performance_stats['peak_memory'], metrics.memory_percent
        )
    
    def _check_alerts(self, metrics: PerformanceMetrics):
        """检查警报条件"""
        # CPU 警报
        self._check_threshold_alert(
            metrics, 'cpu_percent', metrics.cpu_percent, 'CPU使用率'
        )
        
        # 内存警报
        self._check_threshold_alert(
            metrics, 'memory_percent', metrics.memory_percent, '内存使用率'
        )
        
        # 磁盘警报
        self._check_threshold_alert(
            metrics, 'disk_percent', metrics.disk_usage_percent, '磁盘使用率'
        )
        
        # 线程数警报
        self._check_threshold_alert(
            metrics, 'active_threads', metrics.active_threads, '活跃线程数'
        )
    
    def _check_threshold_alert(self, 
                             metrics: PerformanceMetrics,
                             metric_name: str,
                             value: float,
                             display_name: str):
        """检查阈值警报"""
        if metric_name in self.alert_thresholds:
            thresholds = self.alert_thresholds[metric_name]
            
            if value >= thresholds['critical']:
                severity = 'critical'
            elif value >= thresholds['warning']:
                severity = 'warning'
            else:
                return
            
            # 创建警报
            alert = ResourceAlert(
                timestamp=metrics.timestamp,
                alert_type=metric_name,
                message=f"{display_name}过高: {value:.1f}%",
                severity=severity,
                value=value,
                threshold=thresholds[severity]
            )
            
            # 添加到警报列表
            self.alerts.append(alert)
            self.performance_stats['alert_count'] += 1
            
            # 调用回调函数
            if self.alert_callback:
                self.alert_callback(alert)
    
    def get_current_metrics(self) -> Optional[PerformanceMetrics]:
        """获取当前指标"""
        if self.metrics_history:
            return self.metrics_history[-1]
        return None
    
    def get_metrics_history(self, 
                          duration: float = None) -> List[PerformanceMetrics]:
        """
        获取历史指标
        
        Args:
            duration: 时间范围（秒），None 表示全部
            
        Returns:
            List[PerformanceMetrics]: 历史指标列表
        """
        if duration is None:
            return list(self.metrics_history)
        
        current_time = time.time()
        return [
            m for m in self.metrics_history
            if current_time - m.timestamp <= duration
        ]
    
    def get_stats(self) -> Dict[str, Any]:
        """获取统计信息"""
        stats = self.performance_stats.copy()
        
        # 添加当前状态
        current = self.get_current_metrics()
        if current:
            stats['current'] = asdict(current)
        
        # 添加警报统计
        stats['alert_stats'] = {
            'total_alerts': len(self.alerts),
            'warning_alerts': len([a for a in self.alerts if a.severity == 'warning']),
            'critical_alerts': len([a for a in self.alerts if a.severity == 'critical'])
        }
        
        return stats
    
    def export_metrics(self, 
                      format: str = 'json',
                      duration: float = None,
                      file_path: str = None) -> str:
        """
        导出指标数据
        
        Args:
            format: 导出格式（json, csv）
            duration: 时间范围
            file_path: 文件路径
            
        Returns:
            str: 导出的数据
        """
        metrics = self.get_metrics_history(duration)
        
        if format == 'json':
            # 转换为可序列化的格式
            data = {
                'metrics': [asdict(m) for m in metrics],
                'stats': self.get_stats(),
                'export_time': datetime.now().isoformat()
            }
            
            output = json.dumps(data, indent=2, ensure_ascii=False)
            
        elif format == 'csv':
            import csv
            import io
            
            output = io.StringIO()
            writer = csv.writer(output)
            
            # 写入表头
            headers = [
                'timestamp', 'cpu_percent', 'memory_percent', 'memory_used_mb',
                'disk_usage_percent', 'network_sent_mb', 'network_recv_mb',
                'active_threads', 'active_connections'
            ]
            writer.writerow(headers)
            
            # 写入数据
            for m in metrics:
                row = [
                    m.timestamp, m.cpu_percent, m.memory_percent, m.memory_used_mb,
                    m.disk_usage_percent, m.network_sent_mb, m.network_recv_mb,
                    m.active_threads, m.active_connections
                ]
                writer.writerow(row)
            
            output = output.getvalue()
        else:
            raise ValueError(f"不支持的格式: {format}")
        
        if file_path:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(output)
        
        return output
    
    def clear_history(self):
        """清空历史数据"""
        self.metrics_history.clear()
        self.alerts.clear()
        
        # 重置统计
        self.performance_stats = {
            'total_samples': 0,
            'avg_cpu': 0.0,
            'avg_memory': 0.0,
            'peak_cpu': 0.0,
            'peak_memory': 0.0,
            'alert_count': 0
        }


class PerformanceDashboard:
    """性能仪表板（简单的控制台显示）"""
    
    def __init__(self, monitor: PerformanceMonitor):
        """
        初始化仪表板
        
        Args:
            monitor: 性能监控器
        """
        self.monitor = monitor
        self.running = False
        self.display_thread = None
    
    def start(self, update_interval: float = 2.0):
        """启动仪表板"""
        if self.running:
            return
        
        self.running = True
        self.update_interval = update_interval
        
        self.display_thread = threading.Thread(target=self._display_loop)
        self.display_thread.daemon = True
        self.display_thread.start()
    
    def stop(self):
        """停止仪表板"""
        self.running = False
        if self.display_thread:
            self.display_thread.join(timeout=1.0)
    
    def _display_loop(self):
        """显示循环"""
        import os
        
        while self.running:
            try:
                # 清屏
                os.system('clear' if os.name == 'posix' else 'cls')
                
                # 显示性能指标
                self._display_metrics()
                
                # 等待下次更新
                time.sleep(self.update_interval)
                
            except KeyboardInterrupt:
                break
            except Exception as e:
                print(f"显示错误: {e}")
                time.sleep(1.0)
    
    def _display_metrics(self):
        """显示性能指标"""
        metrics = self.monitor.get_current_metrics()
        stats = self.monitor.get_stats()
        
        print("="*60)
        print("性能监控仪表板")
        print("="*60)
        
        if metrics:
            print(f"\n当前状态 ({datetime.fromtimestamp(metrics.timestamp).strftime('%H:%M:%S')}):")
            print(f"CPU 使用率:     {metrics.cpu_percent:6.1f}%")
            print(f"内存使用率:     {metrics.memory_percent:6.1f}% ({metrics.memory_used_mb:6.1f}MB)")
            print(f"磁盘使用率:     {metrics.disk_usage_percent:6.1f}%")
            print(f"网络发送:       {metrics.network_sent_mb:6.2f} MB/s")
            print(f"网络接收:       {metrics.network_recv_mb:6.2f} MB/s")
            print(f"活跃线程:       {metrics.active_threads:6d}")
            print(f"活跃连接:       {metrics.active_connections:6d}")
        
        print(f"\n统计信息:")
        print(f"总采样数:       {stats['total_samples']:6d}")
        print(f"平均 CPU:       {stats['avg_cpu']:6.1f}%")
        print(f"平均内存:       {stats['avg_memory']:6.1f}%")
        print(f"峰值 CPU:       {stats['peak_cpu']:6.1f}%")
        print(f"峰值内存:       {stats['peak_memory']:6.1f}%")
        
        if 'alert_stats' in stats:
            print(f"总警报数:       {stats['alert_stats']['total_alerts']:6d}")
            print(f"警告警报:       {stats['alert_stats']['warning_alerts']:6d}")
            print(f"严重警报:       {stats['alert_stats']['critical_alerts']:6d}")
        
        # 显示最近的警报
        if self.monitor.alerts:
            print(f"\n最近警报:")
            for alert in list(self.monitor.alerts)[-3:]:
                timestamp = datetime.fromtimestamp(alert.timestamp).strftime('%H:%M:%S')
                print(f"[{timestamp}] {alert.severity.upper()}: {alert.message}")
        
        print("\n按 Ctrl+C 退出")


def test_performance_monitor():
    """测试性能监控"""
    print("测试性能监控...")
    
    # 创建监控器
    monitor = PerformanceMonitor(
        sampling_interval=0.5,
        history_size=100,
        enable_alerts=True
    )
    
    # 设置回调
    def on_metric(metrics: PerformanceMetrics):
        # 可以在这里处理指标数据
        pass
    
    def on_alert(alert: ResourceAlert):
        print(f"\n警报! {alert.severity}: {alert.message}")
    
    monitor.set_metric_callback(on_metric)
    monitor.set_alert_callback(on_alert)
    
    # 启动监控
    monitor.start()
    
    try:
        # 启动仪表板
        dashboard = PerformanceDashboard(monitor)
        dashboard.start()
        
        # 模拟一些工作负载
        print("\n模拟工作负载...")
        for i in range(10):
            monitor.add_custom_metric('workload', i * 10)
            time.sleep(1)
        
        # 等待用户中断
        while True:
            time.sleep(1)
            
    except KeyboardInterrupt:
        print("\n停止监控...")
    finally:
        dashboard.stop()
        monitor.stop()
        
        # 导出数据
        print("导出监控数据...")
        json_data = monitor.export_metrics('json', duration=30, file_path='performance_metrics.json')
        print("监控数据已保存到: performance_metrics.json")
        
        # 打印统计信息
        stats = monitor.get_stats()
        print("\n最终统计:")
        for key, value in stats.items():
            print(f"{key}: {value}")


if __name__ == "__main__":
    test_performance_monitor()